import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


public class UDPFileClient extends FileClient {

	  private int bufferSize; // in bytes
	  private InetAddress remote;
	  private DatagramSocket ds;
	  
	  private byte[] receiveBuffer;
	  
	  private HashMap<Integer, FilePart> partList;
	
	public UDPFileClient(String hostName, int port) throws UnknownHostException, SocketException {
		super(hostName, port);
		
		remote = InetAddress.getByName(hostName);
		ds = new DatagramSocket();
		this.bufferSize = 20480; //20Kb
		receiveBuffer = new byte[bufferSize];
		
		partList = new HashMap<Integer, FilePart>();
		
	}

	@Override
	public void CallServer() {
		// TODO Auto-generated method stub
		ds.connect(remote, getPort());		
	    try {
	        BufferedReader inFormUser= new BufferedReader(new InputStreamReader(System.in));// Tao input stream

	        String message = "";
	        String ketQua = "";
	        
	        boolean isGetFile = false;
	        boolean isDownloadFile = false;
	        
	        String fileName = "";
	        String filePath = "";
	        File f = null;
	        FileOutputStream outf = null;
	        String downloadFolderPath = System.getProperty("user.dir") + "\\Download\\";
	        
	        while(true){
	          try {
	        	  if(!isGetFile || !isDownloadFile){
	        		message = inFormUser.readLine();// Nhap vao 1 cau
	  	          	if (message.equalsIgnoreCase("bye"))// Gap chuoi quit
	  	          		break;
	  	          	//Gui toi server
	  	            byte[] data = message.getBytes();
	  	            send(data);
	  	            
		  	          if(message.length() >= 4 && message.substring(0, 4).equalsIgnoreCase("get ")){
		                	//ready for revcive
		                	partList.clear();
		                	
		                	fileName = message.substring(4).trim();
		                	filePath = downloadFolderPath + fileName;
		                	isGetFile = true;
		                }
	  	            
	        	  }
	          	
	            //Nhan tu server
	            byte[] result = receive();
	            ketQua = new String(result);
	            
	            
	            if(isGetFile && !isDownloadFile){
	        		if(ketQua.equalsIgnoreCase("101")){
	            		System.out.println("FROM SERVER: File not found !");
	            		isGetFile = false;
	            	}
	            	if(ketQua.equalsIgnoreCase("100")){
	            		System.out.println("FROM SERVER: Rev file...");
	            		f = new File(filePath);
	                	outf = new FileOutputStream(f);

	            		//Gui toi server
		  	            byte[] data = new String("get").getBytes();
		  	            send(data);
		  	            isDownloadFile = true;
	            	}
	            	continue;
	        	}
	            
	            if(isGetFile && isDownloadFile){
	        		if(ketQua.equalsIgnoreCase("199")){
	        			System.out.println("File: " + fileName + " download done !");
	        			int i = 0;
	        			while(!FileUtility.checkFileDone(partList) || i <= partList.keySet().size()*2){
	        				FileUtility.saveFileUpdate(partList, outf);
	        				i++;
	        			}
	        			outf.close();
	        			
	        			isGetFile = isDownloadFile = false;
	        		}else{
	        			//System.out.println("FROM SERVER: "+ketQua);
	        			//Xu ly ket qua
	        			Pattern r = Pattern.compile("<file>(.*)</file><part>(\\d+)</part><length>(\\d+)</length><data>(.*)</data>");
	        			Matcher m = r.matcher(ketQua);
	        			
	        			if (!m.matches( )) continue;
	        			
	        			String fname = m.group(1);
	        			int part = Integer.parseInt(m.group(2));
	        			int length = Integer.parseInt(m.group(3));
	        			String dataStr = m.group(4);
	        			
	            		System.out.println("File: " + fname + "; Part: " + part + "; PacketLength: " + length);
	            		//Luu vao partList
	            		partList.put(new Integer(part), new FilePart(FileUtility.Base64ToBytes(dataStr), 0));
	            		
	            		//save to file
	            		FileUtility.saveFileUpdate(partList, outf);
	            		
	            		//Gui toi server
		  	            byte[] data = new String("get").getBytes();
		  	            send(data);
	        		}
	        		continue;
	        	}
	            
	            System.out.println("FORM SERVER: " + new String(result).trim());
	          }
	          catch (IOException e) {
	            
	          }
	        }
	      }
	      catch (Exception e) {
	        System.err.println(e);
	      }   
	}

	public void send(byte[] content) {
	    try {
			DatagramPacket dp = new DatagramPacket(content, content.length, remote, getPort());
			ds.send(dp);
		} catch (IOException e) {}  
	}

	public byte[] receive() {
		byte[] result = null;
	    try {
			DatagramPacket incoming = new DatagramPacket(receiveBuffer, receiveBuffer.length);
			ds.receive(incoming);
			result = new byte[incoming.getLength()];
			System.arraycopy(incoming.getData(), 0, result, 0, incoming.getLength());
		} catch (IOException e) {}
	    return result;
	}
	
	@Override
	public void showInfo() {
		System.out.println("UDP File Client");
		System.out.println("Connect to: " + getHostName() + " ; Port: " + getPort());
		
	}

}
